package frontend.parser;

import frontend.lexer.*;
import frontend.parser.syntaxtree.*;

import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

/**
 * 解析源代码并构建AST
 *
 * @author 杨凯伟
 * @date 2024/10/13
 */


public class Parser {
    private final PreReadBuffer buf;
    private final ArrayList<GramError> errorList;

    public ArrayList<GramError> getErrorList() {
        return errorList;
    }

    public Parser(Lexer lexer) throws IOException {
        this.buf = new PreReadBuffer(lexer, 3);
        this.errorList = new ArrayList<>();
    }

    /**
     * 判断token是否为某个type
     *
     * @param token 等待判断的token
     * @return boolean
     */
//    private static boolean isMatch(Token token, TKType type) {
//        return token.getType() == type;
//    }
    private static boolean isMatch(Token token, TKType... types) {
        return Arrays.asList(types).contains(token.getType());
    }

    /**
     * 判断token不是为某个type
     *
     * @param token 等待判断的token
     * @param type  需要满足的type
     * @return boolean
     */
    private static boolean isNotMatch(Token token, TKType type) {
        return token.getType() != type;
    }

    private void matchOrThrow(Token token, TKType type) {
        if (isNotMatch(token, type)) {
            System.out.println("Parser:有预定义符号不匹配 ");
            System.out.println(token.getLineno() + " , 当前Token:" + token.getContent() + " , 当前Type:" + token.getType() + " , Assert类型:" + type);
            throw new RuntimeException();
        }
    }

    private void matchOrThrow(Token token, TKType type, TKType type2) {
        if (isNotMatch(token, type) && isNotMatch(token, type2)) {
//            System.err.println("Parser:有预定义符号不匹配 ");
//            System.err.println(token.getLineno() + " " + token.getContent() + " " + token.getType() + " : " + type);
            throw new RuntimeException();
        }
    }

    /**
     * 分隔当前token
     *
     * @param token 当前token
     * @param type  当前token的类型
     * @return {@code Token}
     * @throws IOException
     */
    private Token parseToken(Token token, TKType type) throws IOException {
        matchOrThrow(token, type);
        return buf.readNextToken();
    }

    private Token parseToken(Token token, TKType type, TKType type2) throws IOException {
        matchOrThrow(token, type, type2);
        return buf.readNextToken();
    }

    public SyntaxNode parse() throws IOException {
        Token currToken = buf.readNextToken();

        ParseResult result = parseCompUnit(currToken);
        currToken = result.getNextToken();
        matchOrThrow(currToken, null);  // if not reach end

        return result.getSubtree();
    }

    private ParseResult parseCompUnit(Token currToken) throws IOException {
        CompUnitNode subTree = new CompUnitNode();
        ParseResult result;
        Token preRead, prePreRead;

        preRead = buf.readTokenWithOffset(1);
        prePreRead = buf.readTokenWithOffset(2);
        while (isMatch(currToken, TKType.CONSTTK) || ((isMatch(currToken, TKType.INTTK) || isMatch(currToken, TKType.CHARTK)) && isMatch(preRead, TKType.IDENFR) && isNotMatch(prePreRead, TKType.LPARENT))) {//全局变量

            result = parseDecl(currToken);
            currToken = result.getNextToken();
            subTree.declares.add((DeclNode) result.getSubtree());
            preRead = buf.readTokenWithOffset(1);
            prePreRead = buf.readTokenWithOffset(2);
        }
        preRead = buf.readTokenWithOffset(1);
        while (isMatch(currToken, TKType.VOIDTK) || (isMatch(currToken, TKType.INTTK, TKType.CHARTK) && isMatch(preRead, TKType.IDENFR))) {//函数定义

            result = parseFuncDef(currToken);
            currToken = result.getNextToken();
            subTree.functions.add((FuncDefNode) result.getSubtree());
            preRead = buf.readTokenWithOffset(1);
        }

        result = parseMainFuncDef(currToken);
        currToken = result.getNextToken();
        subTree.mainFunc = (MainFuncDefNode) result.getSubtree();

        return new ParseResult(currToken, subTree);
    }

    private ParseResult parseFuncDef(Token currToken) throws IOException {
        FuncDefNode subTree = new FuncDefNode();
        ParseResult result;

        result = parseFuncType(currToken);
        currToken = result.getNextToken();
        subTree.funcType = (FuncTypeNode) result.getSubtree();
        subTree.ident = currToken.getContent();
        subTree.identLineNum = currToken.getLineno();
        currToken = parseToken(currToken, TKType.IDENFR);
        currToken = parseToken(currToken, TKType.LPARENT);
        if (isMatch(currToken, TKType.INTTK, TKType.CHARTK)) {//有参数

            result = parseFuncFParams(currToken);
            currToken = result.getNextToken();
            subTree.params = (FuncFParamsNode) result.getSubtree();
        }
        if (isMatch(currToken, TKType.RPARENT)) {//无参数
            currToken = buf.readNextToken();
        } else {
            errorList.add(new GramError(currToken.getLineno(), ErrorCode.j));
        }

        result = parseBlock(currToken);
        subTree.block = (BlockNode) result.getSubtree();
        currToken = result.getNextToken();

        return new ParseResult(currToken, subTree);
    }

    private ParseResult parseFuncFParams(Token currToken) throws IOException {
        ParseResult result;
        FuncFParamsNode subTree = new FuncFParamsNode();

        result = parseFuncFParam(currToken);
        currToken = result.getNextToken();
        subTree.params.add((FuncFParamNode) result.getSubtree());
        while (isMatch(currToken, TKType.COMMA)) {
            currToken = buf.readNextToken();
            result = parseFuncFParam(currToken);
            subTree.params.add((FuncFParamNode) result.getSubtree());

            currToken = result.getNextToken();
        }

        return new ParseResult(currToken, subTree);
    }

    //    private ParseResult parseFuncFParam(Token currToken) throws IOException {
//        FuncFParamNode subTree = new FuncFParamNode();
//        ParseResult result;
//
//        result = parseBType(currToken);
//        currToken = result.getNextToken();
//        subTree.type = (BTypeNode) result.getSubtree();
//        subTree.ident = currToken.getContent();
//        subTree.identLineNum = currToken.getLineno();
//        currToken = parseToken(currToken, TKType.IDENFR);
//        if (isMatch(currToken, TKType.LBRACK)) {
//            subTree.dimensions = new ArrayList<>();
//            currToken = buf.readNextToken();
//            if (isMatch(currToken, TKType.RBRACK)) {
//                currToken = buf.readNextToken();
//            } else {
//                errorList.add(new GramError(buf.readPreToken().getLineno(), ErrorCode.k));
//            }
//            while (isMatch(currToken, TKType.LBRACK)) {
//                currToken = buf.readNextToken();
//                result = parseConstExp(currToken);
//                subTree.dimensions.add((ConstExpNode) result.getSubtree());
//                currToken = result.getNextToken();
//                if (isMatch(currToken, TKType.RBRACK)) {
//                    currToken = buf.readNextToken();
//                } else {
//                    errorList.add(new GramError(buf.readPreToken().getLineno(), ErrorCode.k));
//                }
//            }
//        }
//
//        return new ParseResult(currToken, subTree);
//    }
    private ParseResult parseFuncFParam(Token currToken) throws IOException {
        FuncFParamNode subTree = new FuncFParamNode();
        ParseResult result;

        // 解析 BType
        result = parseBType(currToken);
        currToken = result.getNextToken();
        subTree.type = (BTypeNode) result.getSubtree();

        // 解析标识符
        subTree.ident = currToken.getContent();
        subTree.identLineNum = currToken.getLineno();
        currToken = parseToken(currToken, TKType.IDENFR);

        // 解析数组维度
        if (isMatch(currToken, TKType.LBRACK)) {
            subTree.dimensions = new ArrayList<>();
            currToken = parseArrayDimensions(subTree.dimensions);
        }

        return new ParseResult(currToken, subTree);
    }

    private Token parseArrayDimensions(List<ConstExpNode> dimensions) throws IOException {
        Token currToken = buf.readNextToken();
        if (isMatch(currToken, TKType.RBRACK)) {
            currToken = buf.readNextToken();
        } else {
            errorList.add(new GramError(buf.readPreToken().getLineno(), ErrorCode.k));
        }

        while (isMatch(currToken, TKType.LBRACK)) {
            currToken = buf.readNextToken();
            ParseResult result = parseConstExp(currToken);
            dimensions.add((ConstExpNode) result.getSubtree());
            currToken = result.getNextToken();

            if (isMatch(currToken, TKType.RBRACK)) {
                currToken = buf.readNextToken();
            } else {
                errorList.add(new GramError(buf.readPreToken().getLineno(), ErrorCode.k));
            }
        }

        return currToken;
    }

    private ParseResult parseConstExp(Token currToken) throws IOException {
        ConstExpNode subTree = new ConstExpNode();
        ParseResult result;

        result = parseAddExp(currToken);
        currToken = result.getNextToken();
        subTree.addExp = (AddExpNode) result.getSubtree();

        return new ParseResult(currToken, subTree);
    }

    private ParseResult parseAddExp(Token currToken) throws IOException {
        AddExpNode subTree = new AddExpNodeForSingle();
        ParseResult result;

        result = parseMulExp(currToken);
        currToken = result.getNextToken();
        ((AddExpNodeForSingle) subTree).mulExp = (MulExpNode) result.getSubtree();
        while (isMatch(currToken, TKType.PLUS, TKType.MINU)) {
            TKType op = currToken.getType();
            currToken = buf.readNextToken();

            result = parseMulExp(currToken);
            AddExpNodeForDouble newNode = new AddExpNodeForDouble();
            newNode.mulExp = (MulExpNode) result.getSubtree();
            newNode.addExp = subTree;
            newNode.op = op;
            subTree = newNode;
            currToken = result.getNextToken();
        }

        return new ParseResult(currToken, subTree);
    }

    private ParseResult parseMulExp(Token currToken) throws IOException {
        MulExpNode subTree = new MulExpNodeForSingle();
        ParseResult result;

        result = parseUnaryExp(currToken);
        currToken = result.getNextToken();
        ((MulExpNodeForSingle) subTree).unaryExp = (UnaryExpNode) result.getSubtree();
        while (isMatch(currToken, TKType.MULT, TKType.DIV, TKType.MOD)) {
            TKType op = currToken.getType();
            currToken = buf.readNextToken();

            result = parseUnaryExp(currToken);
            MulExpNodeForDouble newNode = new MulExpNodeForDouble();
            newNode.unaryExp = (UnaryExpNode) result.getSubtree();
            newNode.mulExp = subTree;
            newNode.op = op;
            subTree = newNode;
            currToken = result.getNextToken();
        }

        return new ParseResult(currToken, subTree);
    }

    private ParseResult parseUnaryExp(Token currToken) throws IOException {
        UnaryExpNode subTree = null;
        ParseResult result;
        Token preRead = buf.readTokenWithOffset(1);
        if (isMatch(currToken, TKType.LPARENT, TKType.INTCON, TKType.CHRCON) || (isMatch(currToken, TKType.IDENFR) && isNotMatch(preRead, TKType.LPARENT))) {
            var newNode = new UnaryExpNodeForPrimaryExp();

            result = parsePrimaryExp(currToken);
            currToken = result.getNextToken();
            newNode.primaryExp = (PrimaryExpNode) result.getSubtree();
            subTree = newNode;
        } else if (isMatch(currToken, TKType.IDENFR, TKType.LPARENT)) {
            var newNode = new UnaryExpNodeForFuncCall();
            newNode.ident = currToken.getContent();
            newNode.identLineNum = currToken.getLineno();
            currToken = parseToken(currToken, TKType.IDENFR);
            currToken = parseToken(currToken, TKType.LPARENT);
            if (isMatch(currToken, TKType.LPARENT, TKType.IDENFR, TKType.INTCON, TKType.CHRCON, TKType.PLUS, TKType.MINU)) {

                result = parseFuncRParams(currToken);
                currToken = result.getNextToken();
                newNode.params = (FuncRParamsNode) result.getSubtree();
            }
            if (isMatch(currToken, TKType.RPARENT)) {
                currToken = buf.readNextToken();
            } else {
                errorList.add(new GramError(buf.readPreToken().getLineno(), ErrorCode.j));
            }
            subTree = newNode;
        } else if (isMatch(currToken, TKType.PLUS, TKType.MINU, TKType.NOT)) {
            var newNode = new UnaryExpNodeForUnaryOp();

            result = parseUnaryOp(currToken);
            currToken = result.getNextToken();
            newNode.op = (UnaryOpNode) result.getSubtree();

            result = parseUnaryExp(currToken);
            currToken = result.getNextToken();
            newNode.exp = (UnaryExpNode) result.getSubtree();
            subTree = newNode;
        }

        return new ParseResult(currToken, subTree);
    }

    private ParseResult parseUnaryOp(Token currToken) throws IOException {
        UnaryOpNode subTree = new UnaryOpNode();
//        if (isMatch(currToken, TKType.PLUS)
//                || isMatch(currToken, TKType.MINU)
//                || isMatch(currToken, TKType.NOT)) {
//            subTree.opType = currToken.getType();
//            currToken = buf.readNextToken();
//        }
        switch (currToken.getType()) {
            case PLUS, MINU, NOT -> {
                subTree.opType = currToken.getType();
                currToken = buf.readNextToken();
            }
        }
        return new ParseResult(currToken, subTree);
    }

    private ParseResult parseFuncRParams(Token currToken) throws IOException {
        FuncRParamsNode subTree = new FuncRParamsNode();
        ParseResult result;

        result = parseExp(currToken);
        currToken = result.getNextToken();
        subTree.exps.add((ExpNode) result.getSubtree());
        while (isMatch(currToken, TKType.COMMA)) {
            currToken = buf.readNextToken();

            result = parseExp(currToken);
            currToken = result.getNextToken();
            subTree.exps.add((ExpNode) result.getSubtree());
        }
        return new ParseResult(currToken, subTree);
    }

    private ParseResult parseExp(Token currToken) throws IOException {
        ExpNode subTree = new ExpNode();
        ParseResult result;

        result = parseAddExp(currToken);
        currToken = result.getNextToken();
        subTree.addExp = (AddExpNode) result.getSubtree();

        return new ParseResult(currToken, subTree);
    }

    private ParseResult parsePrimaryExp(Token currToken) throws IOException {
        PrimaryExpNode subTree = null;
        ParseResult result;

//        if (isMatch(currToken, TKType.LPARENT)) {
//            currToken = buf.readNextToken();
//            var newNode = new PrimaryExpNodeForExp();
//
//            result = parseExp(currToken);
//            currToken = result.getNextToken();
//            newNode.exp = (ExpNode) result.getSubtree();
//            subTree = newNode;
//            if (isMatch(currToken, TKType.RPARENT)) {
//                currToken = buf.readNextToken();
//            } else {
//                errorList.add(new GramError(buf.readPreToken().getLineno(), ErrorCode.j));
//            }
//        } else if (isMatch(currToken, TKType.IDENFR)) {
//            var newNode = new PrimaryExpNodeForLVal();
//
//            result = parseLVal(currToken);
//            currToken = result.getNextToken();
//            newNode.lVal = (LValNode) result.getSubtree();
//            subTree = newNode;
//        } else if (isMatch(currToken, TKType.INTCON)) {
//            var newNode = new PrimaryExpNodeForNumber();
//
//            result = parseNumber(currToken);
//            currToken = result.getNextToken();
//            newNode.number = (NumberNode) result.getSubtree();
//            subTree = newNode;
//        } else if (isMatch(currToken, TKType.CHRCON)) {
//            var newNode = new PrimaryExpNodeForCharacter();
//
//            result = parseCharacter(currToken);
//            currToken = result.getNextToken();
//            newNode.character = (CharacterNode) result.getSubtree();
//            subTree = newNode;
//        }
        switch (currToken.getType()) {
            case LPARENT -> {
                currToken = buf.readNextToken();
                var newNode = new PrimaryExpNodeForExp();
                result = parseExp(currToken);
                currToken = result.getNextToken();
                newNode.exp = (ExpNode) result.getSubtree();
                subTree = newNode;
                if (isMatch(currToken, TKType.RPARENT)) {
                    currToken = buf.readNextToken();
                } else {
                    errorList.add(new GramError(buf.readPreToken().getLineno(), ErrorCode.j));
                }
            }
            case IDENFR -> {
                var newNode = new PrimaryExpNodeForLVal();
                result = parseLVal(currToken);
                currToken = result.getNextToken();
                newNode.lVal = (LValNode) result.getSubtree();
                subTree = newNode;
            }
            case INTCON -> {
                var newNode = new PrimaryExpNodeForNumber();
                result = parseNumber(currToken);
                currToken = result.getNextToken();
                newNode.number = (NumberNode) result.getSubtree();
                subTree = newNode;
            }
            case CHRCON -> {
                var newNode = new PrimaryExpNodeForCharacter();
                result = parseCharacter(currToken);
                currToken = result.getNextToken();
                newNode.character = (CharacterNode) result.getSubtree();
                subTree = newNode;
            }
        }
        return new ParseResult(currToken, subTree);
    }

    private ParseResult parseLVal(Token currToken) throws IOException {
        LValNode subTree = new LValNode();
        ParseResult result;

        subTree.ident = currToken.getContent();
        subTree.identLineNum = currToken.getLineno();
        currToken = parseToken(currToken, TKType.IDENFR);
        while (isMatch(currToken, TKType.LBRACK)) {
            currToken = buf.readNextToken();

            result = parseExp(currToken);
            currToken = result.getNextToken();
            subTree.dimensions.add((ExpNode) result.getSubtree());

            if (isMatch(currToken, TKType.RBRACK)) {
                currToken = buf.readNextToken();
            } else {//缺少 ]
                errorList.add(new GramError(buf.readPreToken().getLineno(), ErrorCode.k));
            }
        }

        return new ParseResult(currToken, subTree);
    }

    private ParseResult parseNumber(Token currToken) throws IOException {
        NumberNode subTree = new NumberNode();
        subTree.intConst = currToken.getContent();
        currToken = parseToken(currToken, TKType.INTCON);

        return new ParseResult(currToken, subTree);
    }

    private ParseResult parseCharacter(Token currToken) throws IOException {
        CharacterNode subTree = new CharacterNode();
        subTree.charConst = currToken.getContent();
        currToken = parseToken(currToken, TKType.CHRCON);

        return new ParseResult(currToken, subTree);
    }

    private ParseResult parseBType(Token currToken) throws IOException {
        BTypeNode subTree = new BTypeNode(currToken.getType());
        subTree.type = currToken.getType();

        currToken = parseToken(currToken, TKType.INTTK, TKType.CHARTK);
        return new ParseResult(currToken, subTree);
    }

    private ParseResult parseBlock(Token currToken) throws IOException {
        BlockNode subTree = new BlockNode();
        ParseResult result;

        currToken = parseToken(currToken, TKType.LBRACE);
        while (isNotMatch(currToken, TKType.RBRACE)) {//循环遍历 {} 内部所有元素

            result = parseBlockItem(currToken);
            currToken = result.getNextToken();
            subTree.blockItems.add((BlockItemNode) result.getSubtree());
        }
        subTree.blockRLineNum = currToken.getLineno();
        currToken = buf.readNextToken();

        return new ParseResult(currToken, subTree);
    }

    private ParseResult parseBlockItem(Token currToken) throws IOException {
        BlockItemNode subTree;
        ParseResult result;

//        if (isMatch(currToken, TKType.INTTK)
//                || isMatch(currToken, TKType.CHARTK)
//                || isMatch(currToken, TKType.CONSTTK)) {
//            var newNode = new BlockItemNodeForDecl();
//
//            result = parseDecl(currToken);
//            currToken = result.getNextToken();
//            newNode.decl = (DeclNode) result.getSubtree();
//
//            subTree = newNode;
//        } else {
//            var newNode = new BlockItemNodeForStmt();
//
//            result = parseStmt(currToken);
//            currToken = result.getNextToken();
//            newNode.stmt = (StmtNode) result.getSubtree();
//
//            subTree = newNode;
//        }
        switch (currToken.getType()) {
            case INTTK, CHARTK, CONSTTK -> {
                var newNode = new BlockItemNodeForDecl();

                result = parseDecl(currToken);
                currToken = result.getNextToken();
                newNode.decl = (DeclNode) result.getSubtree();

                subTree = newNode;
            }
            default -> {
                var newNode = new BlockItemNodeForStmt();

                result = parseStmt(currToken);
                currToken = result.getNextToken();
                newNode.stmt = (StmtNode) result.getSubtree();

                subTree = newNode;
            }
        }

        return new ParseResult(currToken, subTree);
    }

    /**
     * 解析Stmt
     *
     * @param currToken 当前Token
     * @return {@code ParseResult}
     * @throws IOException
     */
    private ParseResult parseStmt(Token currToken) throws IOException {
        StmtNode subTree = null;
        ParseResult result;
//        for (Token tk : buf.getReadTokens()) {
//            if (tk != null)
//                System.out.print(tk.getContent() + " ");
//        }
//        System.out.println();
        if (isMatch(currToken, TKType.IDENFR) && (buf.findUntil(TKType.ASSIGN, TKType.SEMICN))) {//LVal赋值语句
            buf.saveReadTokens();
            try {
                LValNode tmpLVal;

                result = parseLVal(currToken);
                currToken = result.getNextToken();
                tmpLVal = (LValNode) result.getSubtree();
                currToken = parseToken(currToken, TKType.ASSIGN);
                if (isMatch(currToken, TKType.GETINTTK, TKType.GETCHARTK)) {//getint
                    StmtNode newNode = null;
                    if (isMatch(currToken, TKType.GETINTTK)) {
                        newNode = new StmtNodeForGetInt();
                        ((StmtNodeForGetInt) newNode).lVal = tmpLVal;
                    } else if (isMatch(currToken, TKType.GETCHARTK)) {
                        newNode = new StmtNodeForGetChar();
                        ((StmtNodeForGetChar) newNode).lVal = tmpLVal;
                    }
                    currToken = buf.readNextToken();
                    currToken = parseToken(currToken, TKType.LPARENT);

                    if (isMatch(currToken, TKType.RPARENT)) {
                        currToken = buf.readNextToken();
                    } else {
                        errorList.add(new GramError(buf.readPreToken().getLineno(), ErrorCode.j));
                    }

                    if (isMatch(currToken, TKType.SEMICN)) {
                        currToken = buf.readNextToken();
                    } else {
                        errorList.add(new GramError(buf.readPreToken().getLineno(), ErrorCode.i));
                    }

                    subTree = newNode;
                } else if (isMatch(currToken, TKType.LPARENT, TKType.IDENFR, TKType.INTCON, TKType.CHRCON, TKType.PLUS, TKType.MINU)) {//表达式语句
                    var newNode = new StmtNodeForAssign();

                    result = parseExp(currToken);
                    currToken = result.getNextToken();
                    newNode.exp = (ExpNode) result.getSubtree();
                    newNode.lVal = tmpLVal;

                    if (isMatch(currToken, TKType.SEMICN)) {
                        currToken = buf.readNextToken();
                    } else {
                        errorList.add(new GramError(buf.readPreToken().getLineno(), ErrorCode.i));
                    }

                    subTree = newNode;
                }
            } catch (Exception e) {
                buf.restoreReadTokens();
                currToken = buf.readTokenWithOffset(0);
//                for (Token tk : buf.getReadTokens()) {
//                    if (tk != null)
//                        System.out.print(tk.getContent() + " ");
//                }
                var newNode = new StmtNodeForExp();

                result = parseExp(currToken);
                currToken = result.getNextToken();
                newNode.exp = (ExpNode) result.getSubtree();

                if (isMatch(currToken, TKType.SEMICN)) {
                    currToken = buf.readNextToken();
                } else {
                    errorList.add(new GramError(buf.readPreToken().getLineno(), ErrorCode.i));
                }

                subTree = newNode;
            }
        } else if (isMatch(currToken, TKType.LPARENT, TKType.IDENFR, TKType.INTCON, TKType.CHRCON, TKType.PLUS, TKType.MINU)) {//Exp
            var newNode = new StmtNodeForExp();

            result = parseExp(currToken);
            currToken = result.getNextToken();
            newNode.exp = (ExpNode) result.getSubtree();

            if (isMatch(currToken, TKType.SEMICN)) {
                currToken = buf.readNextToken();
            } else {
                errorList.add(new GramError(buf.readPreToken().getLineno(), ErrorCode.i));
            }

            subTree = newNode;
        } else if (isMatch(currToken, TKType.SEMICN)) {//空语句，只有分号
            currToken = buf.readNextToken();
            subTree = new StmtNodeForExp();
        } else if (isMatch(currToken, TKType.LBRACE)) {//{，新的块
            var newNode = new StmtNodeForBlock();

            result = parseBlock(currToken);
            currToken = result.getNextToken();
            newNode.block = (BlockNode) result.getSubtree();

            subTree = newNode;
        } else if (isMatch(currToken, TKType.IFTK)) {//IF语句
            var newNode = new StmtNodeForIfElse();

            currToken = buf.readNextToken();
            currToken = parseToken(currToken, TKType.LPARENT);

            result = parseCond(currToken);
            currToken = result.getNextToken();
            newNode.cond = (CondNode) result.getSubtree();

            if (isMatch(currToken, TKType.RPARENT)) {
                currToken = buf.readNextToken();
            } else {
                errorList.add(new GramError(buf.readPreToken().getLineno(), ErrorCode.j));
            }

            result = parseStmt(currToken);
            currToken = result.getNextToken();
            newNode.ifStmt = (StmtNode) result.getSubtree();

            if (isMatch(currToken, TKType.ELSETK)) {
                currToken = buf.readNextToken();

                result = parseStmt(currToken);
                currToken = result.getNextToken();
                newNode.elseStmt = (StmtNode) result.getSubtree();
            }

            subTree = newNode;
        } else if (isMatch(currToken, TKType.FORTK)) {//For语句
            var newNode = new StmtNodeForLoop();

            currToken = buf.readNextToken();
            currToken = parseToken(currToken, TKType.LPARENT);
            if (isMatch(currToken, TKType.IDENFR)) {

                result = parseForStmt(currToken);
                currToken = result.getNextToken();
                newNode.forStmt1 = (ForStmtNode) result.getSubtree();
            }

            if (isMatch(currToken, TKType.SEMICN)) {
                currToken = buf.readNextToken();
            } else {
                errorList.add(new GramError(buf.readPreToken().getLineno(), ErrorCode.i));
            }

            if (isMatch(currToken, TKType.LPARENT, TKType.IDENFR, TKType.INTCON, TKType.CHRCON, TKType.PLUS, TKType.MINU, TKType.NOT)) {

                result = parseCond(currToken);
                currToken = result.getNextToken();
                newNode.cond = (CondNode) result.getSubtree();
            }

            if (isMatch(currToken, TKType.SEMICN)) {
                currToken = buf.readNextToken();
            } else {
                errorList.add(new GramError(buf.readPreToken().getLineno(), ErrorCode.i));
            }

            if (isMatch(currToken, TKType.IDENFR)) {

                result = parseForStmt(currToken);
                currToken = result.getNextToken();
                newNode.forStmt2 = (ForStmtNode) result.getSubtree();
            }

            if (isMatch(currToken, TKType.RPARENT)) {
                currToken = buf.readNextToken();
            } else {
                errorList.add(new GramError(buf.readPreToken().getLineno(), ErrorCode.j));
            }

            result = parseStmt(currToken);
            currToken = result.getNextToken();
            newNode.stmt = (StmtNode) result.getSubtree();

            subTree = newNode;
        } else if (isMatch(currToken, TKType.BREAKTK, TKType.CONTINUETK)) {//break,continue语句
            var newNode = new StmtNodeForContinueBreak();
            newNode.tkLineNum = currToken.getLineno();
            newNode.type = currToken.getType();
            currToken = buf.readNextToken();

            if (isMatch(currToken, TKType.SEMICN)) {
                currToken = buf.readNextToken();
            } else {
                errorList.add(new GramError(buf.readPreToken().getLineno(), ErrorCode.i));
            }

            subTree = newNode;
        } else if (isMatch(currToken, TKType.RETURNTK)) {//return 语句
            var newNode = new StmtNodeForReturn();
            newNode.returnLineNum = currToken.getLineno();
            currToken = buf.readNextToken();

            if (isMatch(currToken, TKType.LPARENT, TKType.IDENFR, TKType.INTCON, TKType.CHRCON, TKType.PLUS, TKType.MINU)) {

                result = parseExp(currToken);
                currToken = result.getNextToken();
                newNode.exp = (ExpNode) result.getSubtree();
            }

            if (isMatch(currToken, TKType.SEMICN)) {
                currToken = buf.readNextToken();
            } else {
                errorList.add(new GramError(buf.readPreToken().getLineno(), ErrorCode.i));
            }

            subTree = newNode;
        } else if (isMatch(currToken, TKType.PRINTFTK)) {//printf语句
            var newNode = new StmtNodeForPrintf();

            newNode.printfLineNum = currToken.getLineno();
            currToken = buf.readNextToken();
            currToken = parseToken(currToken, TKType.LPARENT);
            newNode.StringConst = currToken.getContent();
            currToken = parseToken(currToken, TKType.STRCON);
            while (isMatch(currToken, TKType.COMMA)) {
                currToken = buf.readNextToken();

                result = parseExp(currToken);
                currToken = result.getNextToken();
                newNode.exps.add((ExpNode) result.getSubtree());
            }

            if (isMatch(currToken, TKType.RPARENT)) {
                currToken = buf.readNextToken();
            } else {
                errorList.add(new GramError(buf.readPreToken().getLineno(), ErrorCode.j));
            }

            if (isMatch(currToken, TKType.SEMICN)) {
                currToken = buf.readNextToken();
            } else {
                errorList.add(new GramError(buf.readPreToken().getLineno(), ErrorCode.i));
            }

            subTree = newNode;
        }
        return new ParseResult(currToken, subTree);
    }

    private ParseResult parseCond(Token currToken) throws IOException {
        CondNode subTree = new CondNode();
        ParseResult result;

        result = parseLOrExp(currToken);
        currToken = result.getNextToken();
        subTree.lOrExp = (LOrExpNode) result.getSubtree();

        return new ParseResult(currToken, subTree);
    }

    private ParseResult parseLOrExp(Token currToken) throws IOException {
        LOrExpNode subTree = new LOrExpNodeForSingle();
        ParseResult result;

        result = parseLAndExp(currToken);
        currToken = result.getNextToken();
        ((LOrExpNodeForSingle) subTree).lAndExp = (LAndExpNode) result.getSubtree();

        while (isMatch(currToken, TKType.OR)) {
            currToken = buf.readNextToken();

            result = parseLAndExp(currToken);
            currToken = result.getNextToken();
            LOrExpNodeForDouble newNode = new LOrExpNodeForDouble();
            newNode.lAndExp = (LAndExpNode) result.getSubtree();
            newNode.lOrExp = subTree;
            subTree = newNode;
        }

        return new ParseResult(currToken, subTree);
    }

    private ParseResult parseLAndExp(Token currToken) throws IOException {
        LAndExpNode subTree = new LAndExpNodeForSingle();
        ParseResult result;

        result = parseEqExp(currToken);
        currToken = result.getNextToken();
        ((LAndExpNodeForSingle) subTree).eqExp = (EqExpNode) result.getSubtree();

        while (isMatch(currToken, TKType.AND)) {
            currToken = buf.readNextToken();

            result = parseEqExp(currToken);
            currToken = result.getNextToken();
            LAndExpNodeForDouble newNode = new LAndExpNodeForDouble();
            newNode.eqExp = (EqExpNode) result.getSubtree();
            newNode.lAndExp = subTree;
            subTree = newNode;
        }

        return new ParseResult(currToken, subTree);
    }

    private ParseResult parseEqExp(Token currToken) throws IOException {
        EqExpNode subTree = new EqExpNodeForSingle();
        ParseResult result;

        result = parseRelExp(currToken);
        currToken = result.getNextToken();
        ((EqExpNodeForSingle) subTree).relExp = (RelExpNode) result.getSubtree();

        while (isMatch(currToken, TKType.EQL) || isMatch(currToken, TKType.NEQ)) {
            TKType op = currToken.getType();
            currToken = buf.readNextToken();

            result = parseRelExp(currToken);
            currToken = result.getNextToken();
            EqExpNodeForDouble newNode = new EqExpNodeForDouble();
            newNode.relExp = (RelExpNode) result.getSubtree();
            newNode.eqExp = subTree;
            newNode.op = op;
            subTree = newNode;
        }

        return new ParseResult(currToken, subTree);
    }

    private ParseResult parseRelExp(Token currToken) throws IOException {
        RelExpNode subTree = new RelExpNodeForSingle();
        ParseResult result;

        result = parseAddExp(currToken);
        currToken = result.getNextToken();
        ((RelExpNodeForSingle) subTree).addExp = (AddExpNode) result.getSubtree();

        while (isMatch(currToken, TKType.LSS, TKType.GRE, TKType.LEQ, TKType.GEQ)) {
            TKType op = currToken.getType();
            currToken = buf.readNextToken();

            result = parseAddExp(currToken);
            currToken = result.getNextToken();
            RelExpNodeForDouble newNode = new RelExpNodeForDouble();
            newNode.addExp = (AddExpNode) result.getSubtree();
            newNode.relExp = subTree;
            newNode.op = op;
            subTree = newNode;
        }

        return new ParseResult(currToken, subTree);
    }

    private ParseResult parseForStmt(Token currToken) throws IOException {
        ForStmtNode subTree = new ForStmtNode();
        ParseResult result;

        result = parseLVal(currToken);
        currToken = result.getNextToken();
        subTree.lVal = (LValNode) result.getSubtree();

        currToken = parseToken(currToken, TKType.ASSIGN);

        result = parseExp(currToken);
        currToken = result.getNextToken();
        subTree.exp = (ExpNode) result.getSubtree();

        return new ParseResult(currToken, subTree);
    }

    private ParseResult parseFuncType(Token currToken) throws IOException {
        FuncTypeNode subTree = new FuncTypeNode();

        if (isMatch(currToken, TKType.VOIDTK, TKType.INTTK, TKType.CHARTK)) {
            subTree.type = currToken.getType();

            currToken = buf.readNextToken();
        }
        return new ParseResult(currToken, subTree);
    }

    private ParseResult parseDecl(Token currToken) throws IOException {
        DeclNode subTree = null;
        ParseResult result;

//        if (isMatch(currToken, TKType.CONSTTK)) {//const
//            var newNode = new DeclNodeForConstDecl();
//
//            result = parseConstDecl(currToken);
//            currToken = result.getNextToken();
//            newNode.constDecl = (ConstDeclNode) result.getSubtree();
//
//            subTree = newNode;
//        } else if (isMatch(currToken, TKType.INTTK)) {//int
//            var newNode = new DeclNodeForVarDecl();
//
//            result = parseVarDecl(currToken);
//            currToken = result.getNextToken();
//            newNode.varDecl = (VarDeclNode) result.getSubtree();
//
//            subTree = newNode;
//        } else if (isMatch(currToken, TKType.CHARTK)) {//char
//            var newNode = new DeclNodeForVarDecl();
//
//            result = parseVarDecl(currToken);
//            currToken = result.getNextToken();
//            newNode.varDecl = (VarDeclNode) result.getSubtree();
//
//            subTree = newNode;
//        }
        switch (currToken.getType()) {
            case CONSTTK -> { // const
                var newNode = new DeclNodeForConstDecl();
                result = parseConstDecl(currToken);
                currToken = result.getNextToken();
                newNode.constDecl = (ConstDeclNode) result.getSubtree();
                subTree = newNode;
            }
            case INTTK, CHARTK -> { // int,char
                var newNode = new DeclNodeForVarDecl();
                result = parseVarDecl(currToken);
                currToken = result.getNextToken();
                newNode.varDecl = (VarDeclNode) result.getSubtree();
                subTree = newNode;
            }
        }
        return new ParseResult(currToken, subTree);
    }

    private ParseResult parseConstDecl(Token currToken) throws IOException {
        ConstDeclNode subTree = new ConstDeclNode();
        ParseResult result;

        currToken = parseToken(currToken, TKType.CONSTTK);

        result = parseBType(currToken);
        currToken = result.getNextToken();
        subTree.type = (BTypeNode) result.getSubtree();

        result = parseConstDef(currToken);
        currToken = result.getNextToken();
        subTree.constDefs.add((ConstDefNode) result.getSubtree());

        while (isMatch(currToken, TKType.COMMA)) {
            currToken = buf.readNextToken();

            result = parseConstDef(currToken);
            currToken = result.getNextToken();
            subTree.constDefs.add((ConstDefNode) result.getSubtree());
        }

        if (isMatch(currToken, TKType.SEMICN)) {
            currToken = buf.readNextToken();
        } else {
            errorList.add(new GramError(buf.readPreToken().getLineno(), ErrorCode.i));
        }

        return new ParseResult(currToken, subTree);
    }

    private ParseResult parseConstDef(Token currToken) throws IOException {
        ConstDefNode subTree = new ConstDefNode();
        ParseResult result;

        subTree.ident = currToken.getContent();
        subTree.identLineNum = currToken.getLineno();
        currToken = parseToken(currToken, TKType.IDENFR);
        while (isMatch(currToken, TKType.LBRACK)) {
            currToken = buf.readNextToken();

            result = parseConstExp(currToken);
            currToken = result.getNextToken();
            subTree.dimensions.add((ConstExpNode) result.getSubtree());

            if (isMatch(currToken, TKType.RBRACK)) {
                currToken = buf.readNextToken();
            } else {
                errorList.add(new GramError(buf.readPreToken().getLineno(), ErrorCode.k));
            }
        }
        currToken = parseToken(currToken, TKType.ASSIGN);

        result = parseConstInitVal(currToken);
        currToken = result.getNextToken();
        subTree.constInitVal = (ConstInitValNode) result.getSubtree();

        return new ParseResult(currToken, subTree);
    }

    private ParseResult parseConstInitVal(Token currToken) throws IOException {
        ConstInitValNode subTree = null;
        ParseResult result;

        if (isMatch(currToken, TKType.LPARENT, TKType.IDENFR, TKType.INTCON, TKType.CHRCON, TKType.PLUS, TKType.MINU)) {//表达式初始值
            var newNode = new ConstInitValNodeForConstExp();

            result = parseConstExp(currToken);
            currToken = result.getNextToken();
            newNode.constExp = (ConstExpNode) result.getSubtree();

            subTree = newNode;
        } else if (isMatch(currToken, TKType.LBRACE)) {//数组初始化
            var newNode = new ConstInitValNodeForArrayInit();
            currToken = buf.readNextToken();
            if (isNotMatch(currToken, TKType.RBRACE)) {// []形式

                result = parseConstExp(currToken);
                currToken = result.getNextToken();
                newNode.initValues.add((ConstExpNode) result.getSubtree());

                while (isMatch(currToken, TKType.COMMA)) {
                    currToken = buf.readNextToken();

                    result = parseConstExp(currToken);
                    currToken = result.getNextToken();
                    newNode.initValues.add((ConstExpNode) result.getSubtree());
                }
            }
            currToken = parseToken(currToken, TKType.RBRACE);

            subTree = newNode;
        } else if (isMatch(currToken, TKType.STRCON)) {// "" 字符串形式
            var newNode = new ConstInitValNodeForStringCon();
            newNode.stringConst = currToken.getContent();
            currToken = parseToken(currToken, TKType.STRCON);
            subTree = newNode;
        }

        return new ParseResult(currToken, subTree);
    }

    private ParseResult parseVarDecl(Token currToken) throws IOException {
        VarDeclNode subTree = new VarDeclNode();
        ParseResult result;

        result = parseBType(currToken);
        currToken = result.getNextToken();
        subTree.type = (BTypeNode) result.getSubtree();

        result = parseVarDef(currToken);
        currToken = result.getNextToken();
        subTree.varDefs.add((VarDefNode) result.getSubtree());

        while (isMatch(currToken, TKType.COMMA)) {
            currToken = buf.readNextToken();

            result = parseVarDef(currToken);
            currToken = result.getNextToken();
            subTree.varDefs.add((VarDefNode) result.getSubtree());
        }

        if (isMatch(currToken, TKType.SEMICN)) {
            currToken = buf.readNextToken();
        } else {
            errorList.add(new GramError(buf.readPreToken().getLineno(), ErrorCode.i));
        }

        return new ParseResult(currToken, subTree);
    }

    private ParseResult parseVarDef(Token currToken) throws IOException {
        VarDefNode subTree = new VarDefNode();
        ParseResult result;

        subTree.ident = currToken.getContent();
        subTree.identLineNum = currToken.getLineno();
        currToken = parseToken(currToken, TKType.IDENFR);
        while (isMatch(currToken, TKType.LBRACK)) {
            currToken = buf.readNextToken();

            result = parseConstExp(currToken);
            currToken = result.getNextToken();
            subTree.dimensions.add((ConstExpNode) result.getSubtree());

            if (isMatch(currToken, TKType.RBRACK)) {
                currToken = buf.readNextToken();
            } else {
                errorList.add(new GramError(buf.readPreToken().getLineno(), ErrorCode.k));
            }
        }
        if (isMatch(currToken, TKType.ASSIGN)) {
            currToken = buf.readNextToken();

            result = parseInitVal(currToken);
            currToken = result.getNextToken();
            subTree.initVal = (InitValNode) result.getSubtree();
        }

        return new ParseResult(currToken, subTree);
    }

    private ParseResult parseInitVal(Token currToken) throws IOException {
        InitValNode subTree = null;
        ParseResult result;

        if (isMatch(currToken, TKType.LPARENT, TKType.IDENFR, TKType.INTCON, TKType.CHRCON, TKType.PLUS, TKType.MINU)) {//表达式初始值
            var newNode = new InitValNodeForExp();

            result = parseExp(currToken);
            currToken = result.getNextToken();
            newNode.exp = (ExpNode) result.getSubtree();

            subTree = newNode;
        } else if (isMatch(currToken, TKType.LBRACE)) {//数组初始化列表
            var newNode = new InitValNodeForArray();

            currToken = buf.readNextToken();
            if (isNotMatch(currToken, TKType.RBRACE)) {

                result = parseExp(currToken);
                currToken = result.getNextToken();
                newNode.initVals.add((ExpNode) result.getSubtree());

                while (isMatch(currToken, TKType.COMMA)) {
                    currToken = buf.readNextToken();

                    result = parseExp(currToken);
                    currToken = result.getNextToken();
                    newNode.initVals.add((ExpNode) result.getSubtree());
                }
            }
            currToken = parseToken(currToken, TKType.RBRACE);

            subTree = newNode;
        } else if (isMatch(currToken, TKType.STRCON)) {
            var newNode = new InitValNodeForString();
            newNode.string = currToken.getContent();
            currToken = parseToken(currToken, TKType.STRCON);
            subTree = newNode;
        }

        return new ParseResult(currToken, subTree);
    }

    private ParseResult parseMainFuncDef(Token currToken) throws IOException {
        MainFuncDefNode subTree = new MainFuncDefNode();
        ParseResult result;

        currToken = parseToken(currToken, TKType.INTTK);
        currToken = parseToken(currToken, TKType.MAINTK);
        currToken = parseToken(currToken, TKType.LPARENT);

        if (isMatch(currToken, TKType.RPARENT)) {
            currToken = buf.readNextToken();
        } else {
            errorList.add(new GramError(buf.readPreToken().getLineno(), ErrorCode.j));
        }

        result = parseBlock(currToken);
        currToken = result.getNextToken();
        subTree.mainBlock = (BlockNode) result.getSubtree();

        return new ParseResult(currToken, subTree);
    }
}







